<?php

/**
 * 路由器应用管理
 * @author clive
 * @date 2012-12-12
 */
class app {
    /*
     * 公用变量与方法定义的开始
     */

    public static $APP_BASE; //1：用于存放“应用文件夹”的主目录
    public static $APP_ROOTDIR; //2：您的“应用文件夹”的绝对路径
    public static $APP_COMPANY; //3：公司名称（类命名的第1部分）
    public static $APP_PROJECT; //4：项目名称（类命名的第2部分）
    public static $APP_NAME; //5：应用名称（是由“公司名称”与“项目名称”的组合，中间是用横线隔开的。）
    public static $APP_MODULE; //6：要调用的模块名称（类命名的第3部分）
    public static $APP_VIEW; //7：要调用的视图名称（类命名的第3部分）
    public static $APP_EXTEND; //8：要继承的项目应用名称（公司名称-项目名称）中间用横线隔开
    public static $CONTROLLER_NAME; //9：控制器名称（就是menuclassname菜单目录，类命名的第4部分）
    public static $ACTION_NAME; //10：行为名称（就是menuitemname菜单项，类命名的第6部分）
    public static $MENU_PATH; //11：菜单路径（是由“控制器名称”与“行为名称”的组合，中间是用下划线隔开的。）

    public static function init() {
        //首先获取“公司名称”与“项目名称”
        $temparr = explode('-', self::$APP_NAME);
        if (count($temparr) == 2) {
            self::$APP_COMPANY = $temparr[0]; //公司名称
            self::$APP_PROJECT = $temparr[1]; //项目名称
        } else {
            die("ERROR: \$APP_NAME IS NOT OK!");
        }
        //获取项目自身的路径
        self::$APP_ROOTDIR = self::$APP_BASE . __DS__ . self::$APP_NAME; // 项目路径
        //1：自动加载类的文件
        spl_autoload_register(array(__CLASS__, 'spl_autoload_suxx'));
        //php_sapi_name:apache2handler
        if (php_sapi_name() != 'cli') {
            //2：获取“控制器名”与“行为”
            self::getctrlname();
            //3：定义一些常量
            self::defineConst();
            //4：运行控制器的行为
            self::run();
        }
    }

    /*
      public static function getMenuClassName($class_name) {
      $i = strpos_int($class_name, '_', 3);
      if ($i) {
      return(substr($class_name, $i + 1));
      }
      return('');
      }
      // */
    /*
     * 公用方法到此结束，后面全为私有方法
     */

    /**
     * 注册自动加载函数
     */
    private static function spl_autoload_suxx($class_name) {
        $mvclist = 'model,view,ctrl'; //MVC架构的名称
        //1：首先获取【当前要加载类】的所属类型$class_type
        $classArr = explode('_', $class_name);
        $classArrCount = count($classArr);
        $classArrUbound = $classArrCount - 1;
        $class_type = $classArr[0]; //类的所属类型
        $appname = $modulename = $menuclassdir = ''; //变量定义：应用名称|模块名称|菜单目录名称
        //先判断是类否属于MVC
        if ($classArrCount >= 2 && is_int(strpos(',' . $mvclist . ',', ',' . $class_type . ','))) {
            if ($classArrUbound >= 4) {
                //2：然后获取【当前要加载类】的其他内容
                self::getclassinfo($class_name, $appname, $modulename, $menuclassdir);
                //3：开始导入用户自定义类的文件
                $appname_dir = str_replace('_', '-', $appname); //要把类名的$appname转换成目录的路径
                $file = self::$APP_BASE . __DS__ . $appname_dir . __DS__ . $class_type . __DS__ . $modulename . __DS__ . $menuclassdir . ".php";
                if (!is_readable($file) && $appname_dir == self::$APP_NAME) {
                    //当要创建的类不存在时，可以自动创建
                    $appname_ext = str_replace('-', '_', self::$APP_EXTEND);
                    $class_name_ext = $class_type . '_' . $appname_ext . '_' . $modulename . '_' . $menuclassdir;
                    eval('class ' . $class_name . ' extends ' . $class_name_ext . '{}');
                    return;
                }
            } else {
                die('the $class_name="' . $class_name . '" is wrong !');
            }
        } else {
            //尝试读取PHP框架中自带的类文件
            $file = dirname(__file__) . __DS__ . $class_name . ".class.php";
        }
        //4：从列表中按顺序获取存在的文件
        if (is_readable($file)) {
            include_once $file;
        } else {
            die('the file can not read :' . $file);
        }
    }

    private static function getclassinfo($class_name, &$appname, &$modulename, &$menuclassdir) {
        $classArr = explode('_', $class_name);
        //2-1：获取[应用名称]($appname)
        $appname = $classArr[1] . '_' . $classArr[2]; //公司名称_项目名称
        //2-2：获取[模块名称]($modulename)
        $modulename = $classArr[3];
        //2-3：获取[菜单目录名称]($menuclassdir)例如:sys_menu|sys_code|default_index
        $menuclassdir_start = strlen($classArr[0] . '_' . $appname . '_' . $modulename) + 1;
        $menuclassdir = substr($class_name, $menuclassdir_start);
    }

    /**
     * 定义常量
     * 
     */
    private static function defineConst() {
        $scriptName = $_SERVER['SCRIPT_NAME'];
        $root = '';
        // 开启伪静态
        if (getCfgVar('cfg_open_rewrite')) {
            $root = str_replace(array('/Public', '/index.php'), array('', ''), $scriptName) . '/';
        } else {
            $root = $scriptName . '/';
        }
        $config = import('config.sysinfo', false, self::$APP_ROOTDIR);
        // 当前控制器名称
        $default_ctrl = isset($config['default_ctrl']) ? $config['default_ctrl'] : '';
        if ($default_ctrl == '')
            $default_ctrl = 'default';
        $default_action = isset($config['default_action']) ? $config['default_action'] : '';
        if ($default_action == '')
            $default_action = 'index';
        self::$CONTROLLER_NAME = empty(self::$CONTROLLER_NAME) ? $default_ctrl : strtolower(self::$CONTROLLER_NAME);
        // 当前操作行为名称
        self::$ACTION_NAME = empty(self::$ACTION_NAME) ? $default_action : strtolower(self::$ACTION_NAME);
        self::$MENU_PATH = self::$CONTROLLER_NAME . '_' . self::$ACTION_NAME; //菜单路径
        //define('CONTROLLER_NAME', self::$CONTROLLER_NAME);
        //define('ACTION_NAME', self::$ACTION_NAME);
    }

    /**
     * 普通URL模式
     */
    private static function usuallyURL() {
        if (isset($_REQUEST['c']) && isset($_REQUEST['a'])) {
            self::$CONTROLLER_NAME = $_REQUEST['c'];
            self::$ACTION_NAME = $_REQUEST['a'];
        }
    }

    /**
     * pathinfo URL模式
     */
    private static function pathinfoURL() {
        $return = false;
        if (isset($_SERVER['PATH_INFO'])) {
            $pathinfo = $_SERVER['PATH_INFO'];
            // 此处解决Nginx上pathinfo对自带的script_name进行替换
            if (stripos($pathinfo, '.php') !== false) {
                $pathinfo = str_replace(basename($_SERVER['SCRIPT_NAME']), '', $pathinfo);
            }
            $pathinfoArr = array_filter(explode('/', $pathinfo));
            if (isset($pathinfoArr[1]) && isset($pathinfoArr[2])) {
                $return = true;
                self::$CONTROLLER_NAME = $pathinfoArr[1];
                self::$ACTION_NAME = $pathinfoArr[2];
            }
            $len = count($pathinfoArr);
            for ($i = 3; $i < $len; $i++)
                $_GET[$pathinfoArr[$i]] = $pathinfoArr[++$i];
            $_REQUEST = array_merge($_REQUEST, $_GET);
        }
        return($return);
    }

    private static function getctrlname() {
        //self::isCLI = (php_sapi_name() == 'cli') ? true : false;
        if (!self::pathinfoURL()) {
            self::usuallyURL();
        }
    }

    /**
     * 执行控制器的方法
     */
    private static function run() {
        //第一步：首先是通过CONTROLLER_NAME与ACTION_NAME去执行Controller层的CLASS类
        $class = 'ctrl_' . self::$APP_COMPANY . '_' . self::$APP_PROJECT . '_' . self::$APP_MODULE . '_' . self::$CONTROLLER_NAME;
        $action = 'action_' . self::$ACTION_NAME;
        $class_obj = new $class();
        $returnarray = array();
        if (method_exists($class_obj, $action)) {
            //开始给控制器类传入该有的属性
            //print_r($_REQUEST);
            $class_obj->search = isset($_REQUEST['search']) ? (is_array($_REQUEST['search']) ? $_REQUEST['search'] : json_decode(base64_decode($_REQUEST['search']), true)) : array();
            $class_obj->pageinfo = isset($_POST['pageinfo']) ? $_POST['pageinfo'] : array(); //2:分页
            $class_obj->order = isset($_POST['order']) ? $_POST['order'] : array(); //3:排序
            $returnarray = $class_obj->$action();
        } else {
            die('no exist : /ctrl/' . $class . '->' . $action . '()');
        }
        //执行成功后获取$returnarray
        //第二步：把$returnarray的值传给View层的CLASS类去执行
        if (strtolower(self::$APP_VIEW) == 'api') {
            $format = isset($_GET['format']) ? $_GET['format'] : '';
            if ($format == 'json') {
                echo json_encode($returnarray);
            } else {
                echo serialize($returnarray);
            }
        } else {
            $class = 'view_' . self::$APP_COMPANY . '_' . self::$APP_PROJECT . '_' . self::$APP_VIEW . '_' . self::$CONTROLLER_NAME;
            $class_obj = new $class($returnarray);
            if (method_exists($class_obj, $action)) {
                $class_obj->$action();
            } else {
                die('no exist method: ' . $class . '->' . $action . '()');
            }
        }
    }

}